package lib

import (
	"errors"
	"fmt"
	"time"

	"github.com/gomodule/redigo/redis"
)

var redisPoolMap map[string]*redis.Pool

func InitRedisPool(ConfRedisMap *RedisMapConf) {
	if ConfRedisMap == nil || ConfRedisMap.List == nil {
		return
	}
	for confName, cfg := range ConfRedisMap.List {
		// host := cfg.ProxyList[0]
		if cfg.ConnTimeout == 0 {
			cfg.ConnTimeout = 50
		}
		if cfg.ReadTimeout == 0 {
			cfg.ReadTimeout = 100
		}
		if cfg.WriteTimeout == 0 {
			cfg.WriteTimeout = 100
		}
		if cfg.Active == 0 {
			cfg.Active = 60000
		}
		if cfg.Idle == 0 {
			cfg.Idle = 1024
		}
		if cfg.IdleTimeout == 0 {
			cfg.IdleTimeout = 120
		}

		redisPoolMap[confName] = newRedisPool(cfg)
	}

}

func newRedisPool(cfg *RedisConf) *redis.Pool {
	return &redis.Pool{
		MaxIdle:     cfg.Idle,
		MaxActive:   cfg.Active,
		IdleTimeout: time.Duration(cfg.IdleTimeout),
		Dial: func() (redis.Conn, error) {
			conn, err := redis.Dial("tcp", cfg.ProxyList[0],
				redis.DialConnectTimeout(time.Duration(cfg.ConnTimeout)),
				redis.DialReadTimeout(time.Duration(cfg.ReadTimeout)),
				redis.DialWriteTimeout(time.Duration(cfg.WriteTimeout)),
				redis.DialPassword(cfg.Password),
			)
			if err != nil {
				return nil, err
			}
			return conn, nil
		},
	}
}

func RedisConfDo(trace *TraceContext, name string, commandName string, args ...interface{}) (interface{}, error) {
	pool, ok := redisPoolMap[name]
	if !ok {
		Log.TagError(trace, "_com_redis_failure", map[string]interface{}{
			"method": commandName,
			"err":    errors.New("RedisConnFactory_error:" + name),
			"bind":   args,
		})
		return nil, errors.New("redis pool not found: " + name)
	}

	c := pool.Get()
	defer c.Close()

	startExecTime := time.Now()
	reply, err := c.Do(commandName, args...)
	endExecTime := time.Now()
	if err != nil {
		Log.TagError(trace, "_com_redis_failure", map[string]interface{}{
			"method":    commandName,
			"err":       err,
			"bind":      args,
			"proc_time": fmt.Sprintf("%fs", endExecTime.Sub(startExecTime).Seconds()),
		})
	} else {
		replyStr, _ := redis.String(reply, nil)
		Log.TagInfo(trace, "_com_redis_success", map[string]interface{}{
			"method":    commandName,
			"bind":      args,
			"reply":     replyStr,
			"proc_time": fmt.Sprintf("%fs", endExecTime.Sub(startExecTime).Seconds()),
		})
	}
	return reply, err
}

func RedisConn(name string) (redis.Conn, error) {
	if redisPoolMap == nil {
		return nil, errors.New("redis pool not found")
	}
	pool, ok := redisPoolMap[name]
	if !ok {
		return nil, errors.New("redis pool not found: " + name)
	}
	c := pool.Get()
	return c, nil
}

// 废弃
// func RedisConnFactory(name string) (redis.Conn, error) {
// 	if ConfRedisMap != nil && ConfRedisMap.List != nil {
// 		for confName, cfg := range ConfRedisMap.List {
// 			if name == confName {
// 				randHost := cfg.ProxyList[rand.Intn(len(cfg.ProxyList))]
// 				if cfg.ConnTimeout == 0 {
// 					cfg.ConnTimeout = 50
// 				}
// 				if cfg.ReadTimeout == 0 {
// 					cfg.ReadTimeout = 100
// 				}
// 				if cfg.WriteTimeout == 0 {
// 					cfg.WriteTimeout = 100
// 				}
// 				c, err := redis.Dial(
// 					"tcp",
// 					randHost,
// 					redis.DialConnectTimeout(time.Duration(cfg.ConnTimeout)*time.Millisecond),
// 					redis.DialReadTimeout(time.Duration(cfg.ReadTimeout)*time.Millisecond),
// 					redis.DialWriteTimeout(time.Duration(cfg.WriteTimeout)*time.Millisecond))
// 				if err != nil {
// 					return nil, err
// 				}
// 				if cfg.Password != "" {
// 					if _, err := c.Do("AUTH", cfg.Password); err != nil {
// 						c.Close()
// 						return nil, err
// 					}
// 				}
// 				if cfg.Db != 0 {
// 					if _, err := c.Do("SELECT", cfg.Db); err != nil {
// 						c.Close()
// 						return nil, err
// 					}
// 				}
// 				return c, nil
// 			}
// 		}
// 	}
// 	return nil, errors.New("create redis conn fail")
// }

// 通过配置 执行redis
// func RedisConfDo(trace *TraceContext, name string, commandName string, args ...interface{}) (interface{}, error) {
// 	c, err := RedisConnFactory(name)
// 	if err != nil {
// 		Log.TagError(trace, "_com_redis_failure", map[string]interface{}{
// 			"method": commandName,
// 			"err":    errors.New("RedisConnFactory_error:" + name),
// 			"bind":   args,
// 		})
// 		return nil, err
// 	}
// 	defer c.Close()

// 	startExecTime := time.Now()
// 	reply, err := c.Do(commandName, args...)
// 	endExecTime := time.Now()
// 	if err != nil {
// 		Log.TagError(trace, "_com_redis_failure", map[string]interface{}{
// 			"method":    commandName,
// 			"err":       err,
// 			"bind":      args,
// 			"proc_time": fmt.Sprintf("%fs", endExecTime.Sub(startExecTime).Seconds()),
// 		})
// 	} else {
// 		replyStr, _ := redis.String(reply, nil)
// 		Log.TagInfo(trace, "_com_redis_success", map[string]interface{}{
// 			"method":    commandName,
// 			"bind":      args,
// 			"reply":     replyStr,
// 			"proc_time": fmt.Sprintf("%fs", endExecTime.Sub(startExecTime).Seconds()),
// 		})
// 	}
// 	return reply, err
// }
